package org.helgoboss.one_filer_commandlet

import org.helgoboss.commandlet._
import org.helgoboss.scala_additions.Implicits._
import org.helgoboss.scala_additions.RichFile
import org.helgoboss.maven.Maven
import org.helgoboss.commandlet_convenience.Implicits._
import java.io.File
import org.helgoboss.ide.Ide
import org.helgoboss.one_filer.OneFiler
import org.helgoboss.obr_facade.ObrFacade
import org.helgoboss.bundle_project_facade.BundleProjectFacade
import org.helgoboss.project_data.ProjectData
import org.helgoboss.commandlet_manager.CommandletManager

class OneFilerCommandlet (
        oneFiler: OneFiler,
        maven: => Option[Maven] = None, 
        obrFacade: => Option[ObrFacade] = None, 
        commandletManager: => Option[CommandletManager] = None,
        ide: => Option[Ide] = None
    ) extends Commandlet {
    
	val id = "org.helgoboss.one-filer"
    
    private val bundleProjectFacade = new BundleProjectFacade(maven, obrFacade, commandletManager)
    
	def execute(context: ExecutionContext) = {
        val options = context.arguments.options
        val out = context.writer

        val givenTargetDir = {
            val optionalTargetDirString = options.qualified.get("targetDir")
            optionalTargetDirString.map(context.resolveFile)
        }

        def determineTargetDir(projectData: ProjectData, deleteIfTemporary: Boolean = true) = {
            val symbolicName = generateSymbolicName(projectData)
            val targetDir = givenTargetDir getOrElse {
                val d = RichFile.tempDir / symbolicName
                if (deleteIfTemporary) {
                    d.deleteRecursively
                    require(!d.exists, "temporary target directory [" + d + "] couldn't be deleted")
                }
                d
            }
            out.println("Target dir: [" + targetDir + "]")
            targetDir
        }
        
        val givenSourceFile = {
            val sourceFileString = options.qualified.get("source") getOrElse context.fail("No source given")
            context.resolveFile(sourceFileString)
        }
                
        /* Mode can be generate for directories and edit | generate | install | deploy | execute for single files. */
        val mode = options.qualified("mode")
        
        val linkSourceFile = options.qualified.get("linkSourceFile") == Some("true")
                
        if (givenSourceFile.isDirectory) {
            mode match {
                case "generate" => 
                    val oneFilersDir = givenSourceFile
                    val targetDir = givenTargetDir getOrElse RichFile.createNonExistingTempFile("one-filer-")
                    out.println("Target dir: [" + targetDir + "]")
                    val projectDatas = oneFiler.extractProjectDatas(oneFilersDir)
                    bundleProjectFacade.generateBundleProjects(projectDatas, targetDir, linkSourceFiles = linkSourceFile)
                    
                case _ =>
                    error("unsupported mode")
            }
        } else {
            val projectData = oneFiler.extractProjectData(givenSourceFile)
            val standaloneDeploymentEnabled = options.qualified.get("enableStandaloneDeployment").isDefined

            mode match {
                case "edit" =>
                    val targetDir = determineTargetDir(projectData)
                    bundleProjectFacade.generateBundleProject(projectData, targetDir, linkSourceFile = true)
                    ide.getOrElse(sys.error("no ide available")).openProject(targetDir)

                case "generate" =>
                    bundleProjectFacade.generateBundleProject(projectData, determineTargetDir(projectData), linkSourceFile = linkSourceFile)

                case "generate-pom" =>
                    bundleProjectFacade.generateBundleProjectPom(projectData, determineTargetDir(projectData, deleteIfTemporary = false))

                case "install" =>
                    bundleProjectFacade.installBundleProject(projectData, context.outputStream)
                    
                case "deploy" =>
                    bundleProjectFacade.deployBundleProject(projectData, context.outputStream, deployProjectDataObrResources = standaloneDeploymentEnabled)
                    
                case "execute" =>
                    val innerContext = new ExecutionContext {
                        val workingDirectory = givenSourceFile.getParentFile
                        val arguments = options.positional.toList
                        val inputStream = context.inputStream
                        val outputStream = context.outputStream
                    }
                    bundleProjectFacade.executeBundleProject(projectData, innerContext, context.outputStream, 
                        deployProjectDataObrResources = standaloneDeploymentEnabled)
            }
        }
        
        //~ terminal.open(innerCommandComponents = shell.getCommandComponentsForOpeningInteractiveShell(startupDir = Some(baseDir)))
        0
	}
    
    private def generateSymbolicName(projectData: ProjectData) = projectData.projectId.groupId + "." + projectData.projectId.artifactId
        
    
}